package cn.yj.register;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.io.*;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.*;

/**
 * @author 永健
 * @since 2022-01-18 16:10
 */
public abstract class AbstractRegisterConfig implements EnvironmentAware {

    private static final Logger log=LoggerFactory.getLogger(AbstractRegisterConfig.class);

    private static Environment env;

    private static final Object lock = new Object();

    @Override
    public void setEnvironment(Environment environment) {
        env = environment;
    }


    public static boolean register(String applicationName, String host) {
        String[] split = host.split(":");
        Provider provider = new Provider(applicationName, split[0], Integer.parseInt(split[1]));
        return recordProvider(provider);
    }

    private static boolean recordProvider(Provider provider) {
        Map<String, Provider> providerMap = getPROVIDER();
        if (providerMap == null) {
            providerMap = new HashMap<>();
        }
        providerMap.put(provider.getAddress(), provider);
        writeToFile(JSON.toJSONString(providerMap));
        log.info("服务注册：" + provider.getAddress());
        return true;
    }



    public static void export(Object object, String beanName) {
        if (object == null) {
            log.info("暴露的服务为空");
            return;
        }
        String host = env.getProperty("spring.rpc.provider.host");
        String[] split = host.split(":");
        exportInterface(split[0], Integer.parseInt(split[1]), object, beanName);
    }

    private static void exportInterface(String ip, Integer port, Object object, String beanName) {

        String serviceKey = ip + ":" + port;

        Map<String, Provider> providerMap = getPROVIDER();
        Provider provider = providerMap.get(serviceKey);

        Set<String> beanNames = provider.getBeanNames();
        Set<String> classBeanNames = provider.getClassBeanNames();
        if (beanNames.contains(beanName)) {
            log.info("当前服务Service已经暴露过了:" + beanName);
            return;
        }
        beanNames.add(beanName);
        classBeanNames.add(object.getClass().getName());
        provider.setClassBeanNames(classBeanNames);
        provider.setBeanNames(beanNames);
        providerMap.put(serviceKey, provider);
        writeToFile(JSON.toJSONString(providerMap));
        Class<?> aClass = object.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            String name = method.getName();
            log.info("暴露接口：ip:" + serviceKey + "," + aClass.getName() + "." + name + "(...)," + beanName +
                    "." + name + "(...)");
        }
    }


    public static String loadBalanceIp(String beanName) {
        List<String> ips = new ArrayList<>();
        Map<String, Provider> PROVIDER = getPROVIDER();

        if (PROVIDER == null){
            return "";
        }

        PROVIDER.entrySet().forEach(map -> {
            Provider value = map.getValue();
            Set<String> beanNames = value.getBeanNames();
            if (beanNames.contains(beanName)) {
                ips.add(map.getKey());
            }
        });
        Random random = new Random();
        String ip = ips.size() > 0? ips.get(random.nextInt(ips.size())) : "";
        log.info("随机算法（负载均衡）获取服务-netty：" + ip);
        System.out.println();
        return ip;
    }

    public static void logout() {
        String host = getHost();
        Map<String, Provider> provider = getPROVIDER();
        if (provider != null) {
            provider.remove(host);
            String str = "";
            if (provider.size() > 0) {
                str = JSON.toJSONString(provider);
            }
            writeToFile(str);
        }
        log.info("剔除服务："+host);
    }

    private static String getHost() {
        return env.getProperty("spring.rpc.provider.host");
    }


    private static Map<String, Provider> getPROVIDER() {
        synchronized (lock) {
            File file =
                    new File("/Volumes/SANDISK/test_group/netty/YJRpc/service-register-center/src/main/resources" +
                            "/host" + ".txt");
            FileInputStream fin = null;
            StringBuffer buffer = new StringBuffer();

            try {
                fin = new FileInputStream(file);
                FileChannel channel = fin.getChannel();
                int capacity = 5000;
                ByteBuffer bf = ByteBuffer.allocate(capacity);
                int length;
                while ((length = channel.read(bf)) != -1) {
                    bf.clear();
                    byte[] bytes = bf.array();
                    buffer.append(new String(bytes, 0, length, "UTF-8"));
                }
                channel.close();
            } catch (FileNotFoundException var18) {
                var18.printStackTrace();
            } catch (IOException var19) {
                var19.printStackTrace();
            } finally {
                if (fin != null) {
                    try {
                        fin.close();
                    } catch (IOException var17) {
                        var17.printStackTrace();
                    }
                }
            }
            if (buffer.toString().equals("")){
                return null;
            }
            Map<String, Provider> stringProviderHashMap = new HashMap<>();
            Map<String, JSONObject> stringProviderMap = JSONObject.parseObject(buffer.toString(), Map.class);
            stringProviderMap.entrySet().forEach(map -> {
                JSONObject value = map.getValue();
                JSONArray array = (JSONArray) value.get("beanNames");
                List<String> beanNames = array.toJavaList(String.class);

                JSONArray array1 = (JSONArray) value.get("classBeanNames");
                List<String> classBeanNames = array1.toJavaList(String.class);

                Provider provider = JSON.parseObject(JSON.toJSONString(value), Provider.class);
                provider.setBeanNames(new HashSet<>(beanNames));
                provider.setClassBeanNames(new HashSet<>(classBeanNames));
                stringProviderHashMap.put(map.getKey(),provider);
            });
            return stringProviderHashMap;
        }
    }

    private static void writeToFile(String text) {
        synchronized (lock) {
            try {
                File file = new File("/Volumes/SANDISK/test_group/netty/YJRpc/service-register-center/src/main" +
                        "/resources" + "/host.txt");
                Writer out = new FileWriter(file);
                out.write(text);
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
